import { promiseObject } from './utils';
import { SUPPORTED_VEHICLE_CLASSES } from './constants';
console.log('SUPPORTED_VEHICLE_CLASSES',SUPPORTED_VEHICLE_CLASSES);

import * as _ from 'lodash';
import * as THREE from "three";
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";

const { hostname } = window.location;
const WEB_SOCKETS_ENDPOINT = `ws://${hostname}:5678/`;

const textureLoader = new THREE.TextureLoader()
function loadMaterial(url) {
  return new THREE.MeshBasicMaterial({
    map: textureLoader.load(`static/${url}`),
  });
}
const mtlLoader = new MTLLoader()


async function loadObjMtl(objFile, mtlFile) {
  return new Promise((resolve, reject) => {
    // console.log('===', `static/${mtlFile}`);
    mtlLoader.load(
      `static/${mtlFile}`,
      materials => {
        materials.preload();
        const objLoader = new OBJLoader();
        objLoader.setMaterials(materials);
        objLoader.load(
          `static/${objFile}`,
          obj => {
            resolve(obj);
          },
          () => { },
          (e) => {
            reject('obj模型加载错误')
          }
        );
      },
      () => { },
      (e) => {
        reject('mtl材质加载错误')
      }
    );
  });
}
function loadVehicles() {
  // 将每个车辆类别映射到所有可能模型的数组中
  return _.mapValues(SUPPORTED_VEHICLE_CLASSES, (v, k) =>
    Promise.all(
      _.map(v.models, async model => {
        const { materialUrl,objectUrl, scale } = model;
        let obj;
        if (materialUrl) {
          if (materialUrl.endsWith('.mtl')) {
            obj = await loadObjMtl(objectUrl, materialUrl);
          } else {
            obj = await loadOBJFile(objectUrl, loadMaterial(materialUrl));
          }
        } else {
          obj = await loadOBJFile(objectUrl);
        }
        if (scale) {
          obj.scale.setScalar(scale);
        }
        return obj;
      }),
    ),
  );
}

export function loadOBJFile(url, material) {
  return new Promise((resolve, reject) => {
    const objLoader = new OBJLoader();
    objLoader.load(
      `static/${url}`,
      obj => {
        if (material) {
          obj.traverse(child => {
            if (child instanceof THREE.Mesh) {
              child.material = material;
            }
          });
        }
        resolve(obj);
      },
      () => { },
      reject,
    );
  });
}

export default async function init() {
  // const simulationState = await fetchJson('/state')
  const network = await fetchJson('/scenarios/bologna-acosta/network');
  const isProjection =
    network.net.location.projParameter.length > 0 && network.net.location.projParameter !== '!';

  const webSocket = new WebSocket(WEB_SOCKETS_ENDPOINT);
  const webSocketPromise = new Promise((resolve, reject) => {
    webSocket.onopen = () => resolve(webSocket);
    webSocket.onerror = reject;
  });
  try {
    const resources = await promiseObject({
      additional: fetchJsonAllowFail('/scenarios/bologna-acosta/additional'),
      vehicles: promiseObject(loadVehicles()),
      arrows: promiseObject({
        left: loadOBJFile('/arrows/LeftArrow.obj'),
        right: loadOBJFile('/arrows/RightArrow.obj'),
        uturn: loadOBJFile('/arrows/UTurnArrow.obj'),
        straight: loadOBJFile('/arrows/StraightArrow.obj'),
      }),
      webSocket: webSocketPromise,
    });



    return {
      ...resources,
      // simulationState,
      network,
      webSocket,
      isProjection,
      sumoRootEl: document.body,
    };
  } catch (e) {
    webSocket.close();
    throw e;
  }

}


async function fetchJson(url) {
  const response = await fetch(`http://localhost:5000${url}`);
  if (response.status !== 200) {
    console.log('non-200', url);
    throw new Error(`Unable to load ${url}, response: ${response}`);
  }

  const val = await response.json();

  console.log(`Loaded ${url}`, val);
  return val;
}

async function fetchJsonAllowFail(url) {
  const response = await fetch(`http://localhost:5000${url}`);
  if (response.status === 404) {
    console.log(`Request for ${url} 404'd.`);
    return null;
  }
  const val = await response.json();
  console.log(`Loaded ${url}`);
  return val;
}